import 'dart:collection';
import 'dart:html';
import 'package:logging/logging.dart';
import 'node.dart' as node;

void logConsole(LogRecord lrec) {
  window.console.log(
      "${lrec.sequenceNumber} ${lrec.time} ${lrec.level} ${lrec.loggerName} ${lrec.message}");
}

/** Log the specified debug [message]. */
void logDebugDiv(LogRecord lrec) {
  final DivElement div = query("#debug_div");
  div.insertBefore(new BRElement(), div.nodes.first);
  div.insertBefore(new Text(
      "${lrec.sequenceNumber} ${lrec.time} ${lrec.level} ${lrec.loggerName} ${lrec.message}"),
      div.nodes.first);
  while (div.nodes.length > 50) {
    div.nodes.removeLast();
  }
}

final Logger logger = new Logger("tash");

final List<String> history = [];
var historyIndex = -1;

node.Node example = new node.Node.root()
    .addNamedChild("1", new node.Node.simple("Content for node #1")
        .addNamedChild("function", new node.Node.simple("fname")))
    .addNamedChild("feat1", new node.Node.simple("Label for node @feat1")
        .addNamedChild("sf1", new node.Node.simple("simple nest")))
    .addNamedChild("feat2", new node.Node.simple("a content"))
    .addNamedChild("tuple-test", new node.Node.simple("Tuple")
        .appendChild(new node.Node.simple("value1"))
        .appendChild(new node.Node.simple("value2"))
        .appendChild(new node.Node.simple("value3")))
    .addNamedChild("feat4", new node.Node.simple("b content"));


class Editor {
  static final Editor instance = new Editor();

  final node.Node root = new node.Node.root();
  node.Node cursor;

  /** Text being edited, if not null. */
  StringBuffer _text = null;
  Element _textElt = null;

  Editor() {
    root.parent = null;
    root.element = query("#editor");
    display(example, root.element);
    cursor = root;
  }

  void editorKeyDown(KeyboardEvent event) {
    logger.info("Editor key down: code=${event.keyCode} char=${event.charCode}");
    switch (event.keyCode) {
      case 13: {  // enter
        event.preventDefault();
      }
      break;
      case 45: {  // insert
        node.Node newNode = new node.Node.simple("new");
        newNode.parent = cursor;

        cursor.features[cursor.features.length] = newNode;
        final TextAreaElement tae = new TextAreaElement();
        tae.classes.add("textarea");
        tae.text = newNode.label;
        // final DivElement div = new DivElement();
        // div.text = newNode.label;
        _textElt = tae;
        _text = new StringBuffer(tae.text);
        cursor.element.append(tae);
        event.preventDefault();
      }
      break;
      case 8: {  // backspace
        if (_text == null) {
          // Not currently editing a text.
        } else {
          final String text = _text.toString();
          if (!text.isEmpty) {
            _text = new StringBuffer(text.substring(0, text.length - 1));
            _textElt.text = _text.toString();
          }
        }
      }
      break;
    }
  }

  void editorKeyPress(KeyboardEvent event) {
    logger.info("Editor key press: code=${event.keyCode} char=${event.charCode}");
  }

}

/**
 * [node] Node to generate display elements for.
 * [root] Root HTML element to generate the display into.
 */
void display(node.Node node, Element root) {
  root.appendText(node.label);
  if (!node.features.isEmpty) {
    final DivElement featDiv = new DivElement();
    featDiv.style.verticalAlign = "top";
    featDiv.style.borderStyle = "solid";
    featDiv.style.borderWidth = "1px";
    root.append(featDiv);
    featDiv.style.marginLeft = "15px";

    for (Object feature in node.features.keys) {
      featDiv.appendText(feature.toString());
      featDiv.appendText(":");
      final DivElement div = new DivElement();
      div.style.display = "inline-block";
      display(node.features[feature], div);
      featDiv.append(div);
      featDiv.append(new BRElement());
    }
  }
}


void main() {
  Logger.root.onRecord.listen(logConsole);
  Logger.root.onRecord.listen(logDebugDiv);

  final TextAreaElement textarea = query("#input_textarea");
  textarea..onKeyDown.listen(keyDown);

  final DivElement editorDiv = query("#editor");
  editorDiv
      ..onFocus.listen((Event event) => logger.info("Focused"))
      ..onKeyDown.listen(Editor.instance.editorKeyDown)
      ..onKeyPress.listen(Editor.instance.editorKeyPress)
      ..focus();
}


void command(String command) {
  history.add(command);
  logger.info("History length: ${history.length}");
  historyIndex = history.length - 1;

  final req = new HttpRequest();
  req
      ..open("POST", "/command", true)
      ..onLoad.listen((ProgressEvent event) => logger.info(req.responseText))
      ..send(command);
}

void keyDown(KeyboardEvent event) {
  logger.info("Key down: code=${event.keyCode} char=${event.charCode}");
  final TextAreaElement textarea = query("#input_textarea");

  switch (event.keyCode) {
    case 13: {  // Enter
      if (event.ctrlKey) {
        final text = textarea.value;
        textarea.value = "";
        command(text);
      }
    }
    break;
    case 38: {  // Up
      if (event.ctrlKey) {
        if (historyIndex < 0) historyIndex = history.length - 1;
        textarea.value = history[historyIndex];
        historyIndex -= 1;
      }
    }
    break;
    case 40: {  // Down
      if (event.ctrlKey) {
        if (historyIndex >= history.length) historyIndex = 0;
        textarea.value = history[historyIndex];
        historyIndex += 1;
      }
    }
    break;
    default: {
    }
  }
}
